package warp

import (
	"reflect"

	"gitee.com/krio/ginc/example/core/exerr"
	logger "gitee.com/krio/ginc/example/core/lib/logger/zaplog"
	"gitee.com/krio/ginc/example/dto/api/route"
	"gitee.com/krio/ginc/example/router/output"
	"gitee.com/krio/ginc/example/util/validater"
	"github.com/gin-gonic/gin"
)

// WrapHandler [标准] 自动绑定参数 + 自动验证 + 自动返回
// 绑定逻辑:
// 注意:
// **** 1. 自定义结构体，尽量要加上form标签
// **** 2. handler 必须是 func(ctx *gin.Context, req Struct) (resp Struct, err error)
// **** 3. 验证详见：github.com/go-playground/validator/v10
func WrapHandler(f interface{}) func(*gin.Context) {
	hv := reflect.ValueOf(f)
	ht := hv.Type()
	// 验证是否是func
	if ht.Kind() != reflect.Func {
		logger.Panicf("处理函数错误：非函数")
	}
	// 返回函数的参数数量
	if ht.NumIn() != 2 {
		logger.Panicf("处理函数错误：入参数量错误")
	}
	// 返回函数的返回值数量
	if ht.NumOut() != 2 {
		logger.Panicf("处理函数错误：出参数量错误")
	}
	// 第一个参数类型固定为： *gin.Context
	if ht.In(0) != reflect.TypeOf(&gin.Context{}) {
		//if valType.In(0).String() != "*gin.Context" {
		logger.Panicf("处理函数错误：入参首参数错误")
	}
	// 第二个参数类型固定为： error
	if !ht.Out(1).Implements(reflect.TypeOf((*error)(nil)).Elem()) {
		//if valType.Out(1).String() != "error" {
		logger.Panicf("处理函数错误：出参次类型必须是error")
	}
	return func(ctx *gin.Context) {
		var (
			request = reflect.New(ht.In(1).Elem()).Interface()
			resp    exerr.IExerr
		)
		defer func() {
			output.Response(ctx, "", resp)
		}()

		// 设置接口返回结构
		info := route.GetRouteByURL(ctx.Request.URL.Path)
		if info == nil {
			resp = exerr.RequestFail.WithSubmsg(ctx.Request.URL.Path)
			return

		}
		ctx.Set(output.ResponseCtxKey, info.GetInfo().Output)

		//err := ctx.ShouldBindUri(&request)
		//if err != nil {
		//	resp = exerr.Err.WithSubmsg(err.Error())
		//	return
		//}		// 自动绑定（支持 JSON、Query、Form、URI）

		// 自动绑定（支持 JSON、Query、Form、URI）
		_ = ctx.ShouldBindUri(request)
		err := ctx.ShouldBind(&request)
		if err != nil {
			resp = exerr.Err.WithSubmsg(err.Error())
			return
		}

		// 数据验证（验证标签：validate）
		checkRes := validater.RequestValidate(request)
		if checkRes != "" {
			resp = exerr.ParamInvalid.WithSubmsg(checkRes)
			return
		}

		// 处理处理error
		result := hv.Call(valOf(ctx, request))
		if !result[1].IsNil() { // has err
			resp = exerr.Parse(result[1].Interface())
			return
		}
		resp = exerr.OK.WithData(result[0].Interface())
	}
}

func valOf(i ...interface{}) []reflect.Value {
	var rt []reflect.Value
	for _, i2 := range i {
		rt = append(rt, reflect.ValueOf(i2))
	}
	return rt
}
